﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace AiQiuQuan.Sport.Core
{
    /// <summary>
    /// BaseDbContext
    /// </summary>
    public class BaseDbContext<TDbContext> : DbContext where TDbContext : DbContext
    {
        /// <summary>
        /// 分表信息
        /// </summary>
        public ISplitTableInfo SplitTableInfo { get; }

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="options">DbContextOptions</param>
        public BaseDbContext(
            DbContextOptions options,
            ISplitTableInfo splitTableInfo)
            : base(options)
        {
            SplitTableInfo = splitTableInfo;
        }

        /// <summary>
        /// ctor
        /// </summary>
        public BaseDbContext(DbContextOptions options)
            : base(options)
        {
        }

        /// <summary>
        /// OnConfiguring
        /// </summary>
        /// <param name="optionsBuilder">DbContextOptionsBuilder</param>
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            if (SplitTableInfo != null)
            {
                optionsBuilder.ReplaceService<IModelCacheKeyFactory, MyModelCacheKeyFactory<TDbContext>>();
            }
        }

        /// <summary>
        /// 实体模型配置
        /// </summary>
        /// <param name="modelBuilder">ModelBuilder</param>
        public virtual void OnModelCreate(ModelBuilder modelBuilder)
        {

        }

        /// <summary>
        /// OnModelCreating
        /// </summary>
        /// <param name="modelBuilder">ModelBuilder</param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            OnModelCreate(modelBuilder);
            foreach (var item in modelBuilder.Model.GetEntityTypes())
            {
                var tt = item.GetProperties().Where(m => m.ClrType == typeof(DateTimeOffset) || m.ClrType == typeof(DateTimeOffset?)).ToList();
                tt.ForEach(m =>
                {
                    m.SetValueConverter(new DateTimeOffsetValueConverter());
                });
            }

            if (SplitTableInfo != null)
            {
                foreach (var item in modelBuilder.Model.GetEntityTypes())
                {
                    var tableName = item.GetTableName();
                    if (!string.IsNullOrWhiteSpace(tableName))
                    {
                        if (!string.IsNullOrWhiteSpace(SplitTableInfo.Prefix) && !tableName.StartsWith(SplitTableInfo.Prefix))
                        {
                            tableName = $"{SplitTableInfo.Prefix}_{tableName}";
                        }

                        if (!string.IsNullOrWhiteSpace(SplitTableInfo.Suffix) && !tableName.EndsWith(SplitTableInfo.Suffix))
                        {
                            tableName = $"{tableName}_{SplitTableInfo.Suffix}";
                        }

                        item.SetTableName(tableName);
                    }
                }
            }
        }
    }

    class DateTimeOffsetValueConverter : ValueConverter<DateTimeOffset?, DateTime?>
    {
        public DateTimeOffsetValueConverter()
            : base(m => m.HasValue ? m.Value.DateTime : null,
                  m => m.HasValue ? m : null,
                  null)
        { }
    }
}
